/**
 * 
 */
package chineseanalyser;

import java.io.IOException;
import java.io.Reader;

import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.Tokenizer;
import org.ictclas4j.bean.MidResult;
import org.ictclas4j.bean.SegNode;
import org.ictclas4j.bean.SegResult;
import org.ictclas4j.segment.Segment;
import org.ictclas4j.utility.POSTag;

import java.nio.*;

/**
 * @author FuLingting
 *
 */
public final class CASChineseTokenizer extends Tokenizer {
	
	private static final int BUFFER_CAPACITY = 1024 / 4;
	
	public CASChineseTokenizer(Reader reader)
	{
		if (null == segTag)
			segTag = new Segment(1);
		this.input = reader;
	}
	
	/**
	 * 󷵻ؿգôȡĵһʡ
	 */
	public Token next(final Token reusableToken) throws IOException
	{
		assert reusableToken != null;
		reusableToken.clear();
		if (segResult == null && !bEOF)
			segResult = getSegResult();
		
		if (null == segResult)
			return null;
		
		do {
			if (nCrrMidResultIdx >= segResult.getMrList().size()) {
				if (!bEOF){
					segResult = getSegResult();
					continue;
				}
				else {
					segResult = null;
					return null;
				}
			}
			else {
				MidResult midResult = segResult.getMrList().get(nCrrMidResultIdx);
				if (nCrrNodeIdx >= midResult.getOptSegGraph().size()) {
					nCrrMidResultIdx++;
					nCrrNodeIdx = 0;
					continue;
				}
				else {
					if (SegNode2Token(nByteOffsetInBuffer, 
						midResult.getOptSegGraph().get(nCrrNodeIdx), reusableToken))
					{
						nByteOffsetInBuffer += reusableToken.termLength();
						nCrrNodeIdx++;
						break;
					}
					else {
						nCrrNodeIdx++;
					}
				}
			}
			
		} while (segResult != null);

		return reusableToken;
	}
	
	public void reset() throws IOException
	{
		super.reset();
		segResult = null;
		nCrrMidResultIdx = 0;
		nCrrNodeIdx = 0;
	}
	
	public void reset(Reader reader) throws IOException{
		reset();
		input = reader;
	}

	private SegResult segResult = null;		// ִʵĽ(SegResultбҪһŻڴ滺˺ܶ಻Ҫм? 2009.7.2?By FLT)
	private static Segment segTag = null;	// 
	private int nCrrMidResultIdx = 0;		//
	private int nCrrNodeIdx = 0;			// ǰı
	private int nByteOffsetInBuffer = 0;	// 
	private int nBlockOffset = 0;			// Ű飨СΪBUFFER_CAPACITYļ뻺档¼ı
	private boolean bEOF = false;
	
	private SegResult getSegResult() throws IOException
	{
		java.nio.CharBuffer chBuffer = CharBuffer.allocate(BUFFER_CAPACITY);
		int nCharCnt = input.read(chBuffer);
		bEOF = nCharCnt < BUFFER_CAPACITY;
		if (nCharCnt > 0) {
			String src = String.valueOf(chBuffer.array()).trim();
			SegResult segResult = segTag.split(src);
			nCrrMidResultIdx = 0;
			nCrrNodeIdx = 0;
			nBlockOffset++;
			return segResult;
		}
		else {
			return null;
		}
	}
	
	/**
	 * ڽŻзִͼнڵתToken
	 * @param nStartOffset 	ʼֵƫ
	 * @param node			ͼڵ
	 * @param token
	 */
	private boolean SegNode2Token(int nStartOffset, SegNode node, Token token){
		assert token != null && nStartOffset >= 0 && node != null;
		token.clear();
		if (POSTag.SEN_BEGIN != node.getPos() && POSTag.SEN_END != node.getPos() && node.getSrcWord().length() > 0) {
			token.setStartOffset(nStartOffset);
			token.setEndOffset(nStartOffset + node.getSrcWord().length());
			token.setPositionIncrement(1);
			token.setTermText(node.getSrcWord());
			token.setType(ChineseUtil.CASPosTag2TokenType(node.getPos()));
			return true;
		}
		else 
			return false;
	}
}
